package com.guohang.mic_01;

import java.text.DecimalFormat;
import java.util.ArrayList;

import org.ioe.tprsa.audio.feature.MFCC;

import weka.clusterers.Cobweb;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import android.os.Messenger;


public class FeatureModel{
	   
	
	   private MFCC mfcc;
	   private Instances mDataset;
	   private Cobweb cw = new Cobweb();
	   private int featureCount;
	   private double[] featureWindow;
	   private int count = 0;
	   private CommentsDataSource dataSource;
	   private BinManager binManager;
	   
	   //constructor
	   public FeatureModel(int frameSize, int sampleRate, int featureCount, CommentsDataSource dataSource, BinManager binManager){
		   
		   //bin manager
		   this.binManager = binManager;
		   
		   //database access
		   this.dataSource = dataSource;
		 
		   this.featureCount = featureCount;
		   //set the window to hold 10 frame i.e. 1.28s
		   this.featureWindow = new double[featureCount * 10];
		   
		 //maths
		    mfcc = new MFCC(frameSize, sampleRate, featureCount);
		    
		 //read model from mobile phone file
				try {
					cw = (Cobweb) weka.core.SerializationHelper.read("/mnt/sdcard/cw.model");
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

		//Build structure for weka to build model for the first time if the model does not exist
		    ArrayList<Attribute> allAttr = new ArrayList<Attribute>();
			DecimalFormat df = new DecimalFormat("0000");
			   
			   for (int i = 0; i < featureCount * 10; i++){
				   Attribute mm = new Attribute("mfcc_feature" + df.format(i));
				   allAttr.add(mm);
			   }
			   
			   mDataset = new Instances("mfcc_features", allAttr, 10000);
		       mDataset.setClassIndex(mDataset.numAttributes() - 1);
		       

 
	   }
	   
	   //in case no existing model found, create new model here
	   private void createNewModel(Instance inst){
	       
		       //build an empty structure for further incremental clustering		       
		       try {
				cw.buildClusterer(mDataset);
			       } catch (Exception e) {
				      // TODO Auto-generated catch block
				      e.printStackTrace();
			      }


			     try {
					cw.updateClusterer(inst);
				     } catch (Exception e) {
					   // TODO Auto-generated catch block
					   e.printStackTrace();
				     }
				   
				   cw.updateFinished();
       
	   }
	   
	   //MFCC feature extraction and model building
	   public void updateModel(float[] mfccFrame){
		   
		   //mfcc feature extraction
	       double[] mfccFeature = mfcc.doMFCC(mfccFrame);
	       
	       if(count < 10){
	    	   for(int i = 0; i < mfccFeature.length; i++){
	    	     featureWindow[count * mfccFeature.length + i] = mfccFeature[i];
	    	   }
	    	   count++;
	    	   return;
	       }else{
	    	   count = 0;
	    	   buildModel(featureWindow);
	    	   featureWindow = new double[featureCount * 10];
	       }
	           	
	    }
	   
	   public void buildModel(double[] featureWindow){
		   //create instance
		   Instance inst = new DenseInstance(featureWindow.length);
		   inst.setDataset(mDataset);
		   
	       for(int i=0; i<featureWindow.length; i++){
				 inst.setValue(i, featureWindow[i]);
		       }	
	       
	       //local existing model
		  /* try {
				cw = (Cobweb) weka.core.SerializationHelper.read("/mnt/sdcard/cw.model");
			} catch (Exception e1) {
				// if model doesnot exist, create new model
				createNewModel(inst);
				e1.printStackTrace();
				return;
			} */
		   
		   if(cw == null){createNewModel(inst); return;}
		   
		   //update existing model with new data
		     try {
				cw.updateClusterer(inst);
			     } catch (Exception e) {
				   // TODO Auto-generated catch block
				   e.printStackTrace();
			     }			   
			   cw.updateFinished();
			   
		  
			try {
				int instNumber = cw.clusterInstance(inst);
				
				//update database
				int count = dataSource.updateCluster(instNumber);
				binManager.updateUI(count);
				
    		    //int clusterNumber = cw.numberOfClusters();
				// double[] instDistribution = cw.distributionForInstance(inst);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	   }
	   
	  public void taskFinish(){
		   try {
			weka.core.SerializationHelper.write("/mnt/sdcard/cw.model", cw);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	  }
	   
}
